package com.flmz.friend.service.user.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.flmz.api.RemoteJudgeService;
import com.flmz.api.domain.UserExeResult;
import com.flmz.api.domain.dto.JudgeSubmitDTO;
import com.flmz.api.domain.vo.UserQuestionResultVO;
import com.flmz.common.core.constants.Constants;
import com.flmz.common.core.domain.R;
import com.flmz.common.core.enums.ProgramType;
import com.flmz.common.core.enums.QuestionResType;
import com.flmz.common.core.enums.ResultCode;
import com.flmz.common.core.utils.ThreadLocalUtil;
import com.flmz.common.security.exception.ServiceException;
import com.flmz.friend.domain.question.Question;
import com.flmz.friend.domain.question.QuestionCase;
import com.flmz.friend.domain.question.es.QuestionES;
import com.flmz.friend.domain.user.UserSubmit;
import com.flmz.friend.domain.user.dto.UserSubmitDTO;
import com.flmz.friend.elasticsearch.QuestionRepository;
import com.flmz.friend.mapper.question.QuestionMapper;
import com.flmz.friend.mapper.user.UserSubmitMapper;
import com.flmz.friend.rabbitmq.JudgeProducer;
import com.flmz.friend.service.user.IUserQuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserQuestionServiceImpl implements IUserQuestionService {

	@Autowired
	private QuestionRepository questionRepository;

	@Autowired
	private QuestionMapper questionMapper;

	@Autowired
	private UserSubmitMapper userSubmitMapper;

	@Autowired
	private RemoteJudgeService remoteJudgeService;

	@Autowired
	private JudgeProducer judgeProducer;

	@Override
	public R<UserQuestionResultVO> submit(UserSubmitDTO submitDTO) {
		Integer programType = submitDTO.getProgramType();
		// 当前只支持Java
		if (ProgramType.JAVA.getValue().equals(programType)) {
			JudgeSubmitDTO judgeSubmitDTO = assembleJudgeSubmitDTO(submitDTO);
			return remoteJudgeService.doJudgeJavaCode(judgeSubmitDTO);
		}
		throw new ServiceException(ResultCode.FAILED_NOT_SUPPORT_PROGRAM);
	}

	// 此处没办法拿到判题后的vo结果，只是提交代码给mq
	@Override
	public boolean rabbitmqSubmit(UserSubmitDTO submitDTO) {
		Integer programType = submitDTO.getProgramType();
		if (ProgramType.JAVA.getValue().equals(programType)) {
			// 按照java逻辑处理
			JudgeSubmitDTO judgeSubmitDTO = assembleJudgeSubmitDTO(submitDTO);
			judgeProducer.produceMsg(judgeSubmitDTO); // 生成消息往mq中放
			return true;
		}
		throw new ServiceException(ResultCode.FAILED_NOT_SUPPORT_PROGRAM);
	}

	@Override
	public UserQuestionResultVO exeResult(Long examId, Long questionId, String currentTime) {
		Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
		UserSubmit userSubmit = userSubmitMapper.selectCurrentUserSubmit(userId, examId, questionId, currentTime);
		UserQuestionResultVO resultVO = new UserQuestionResultVO();
		if (userSubmit == null) {
			resultVO.setPass(QuestionResType.IN_JUDGE.getValue());
		} else {
			resultVO.setPass(userSubmit.getPass());
			resultVO.setExeMessage(userSubmit.getExeMessage());
			if (StrUtil.isNotEmpty(userSubmit.getCaseJudgeRes())) {
				resultVO.setUserExeResultList(JSON.parseArray(userSubmit.getCaseJudgeRes(), UserExeResult.class));
			}
		}
		return resultVO;
	}

	private JudgeSubmitDTO assembleJudgeSubmitDTO(UserSubmitDTO submitDTO) {
		Long questionId = submitDTO.getQuestionId();
		QuestionES questionES = questionRepository.findById(questionId).orElse(null);
		JudgeSubmitDTO judgeSubmitDTO = new JudgeSubmitDTO();
		if (questionES != null) {
			BeanUtil.copyProperties(questionES, judgeSubmitDTO);
		} else {
			Question question = questionMapper.selectById(questionId);
			BeanUtil.copyProperties(question, judgeSubmitDTO);
			questionES = new QuestionES();
			BeanUtil.copyProperties(question, questionES);
			questionRepository.save(questionES);
		}
		// 赋值
		judgeSubmitDTO.setUserId(ThreadLocalUtil.get(Constants.USER_ID, Long.class));
		judgeSubmitDTO.setExamId(submitDTO.getExamId());
		judgeSubmitDTO.setProgramType(submitDTO.getProgramType());
		judgeSubmitDTO.setUserCode(codeConnect(submitDTO.getUserCode(), questionES.getMainFuc()));
		List<QuestionCase> questionCaseList = JSONUtil.toList(questionES.getQuestionCase(), QuestionCase.class);
		List<String> inputList = questionCaseList.stream().map(QuestionCase::getInput).toList();
		judgeSubmitDTO.setInputList(inputList);
		List<String> outputList = questionCaseList.stream().map(QuestionCase::getOutput).toList();
		judgeSubmitDTO.setOutputList(outputList);
		return judgeSubmitDTO;
	}

	// 拼接main函数
	private String codeConnect(String userCode, String mainFunc) {
		String targetCharacter = "}";
		int targetLastIndex = userCode.lastIndexOf(targetCharacter);
		if (targetLastIndex != -1) {
			return userCode.substring(0, targetLastIndex) + "\n" + mainFunc + "\n" + userCode.substring(targetLastIndex);
		}
		throw new ServiceException(ResultCode.FAILED);
	}
}
